package singleton;

import java.util.concurrent.TimeUnit;

/**
 * 单例模式
 */
public class LazySingletonTest1 {
    public static void main(String[] args) {
//        LazySingleton1 lazySingleton1 = LazySingleton1.getInstance();
//        System.out.println(lazySingleton1);
//        LazySingleton1 lazySingleton2 = LazySingleton1.getInstance();
//        System.out.println(lazySingleton2);

//        new Thread(()->{
//            System.out.println(LazySingleton1.getInstance2());
//        }).start();
//        new Thread(()->{
//            System.out.println(LazySingleton1.getInstance2());
//        }).start();


        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                System.out.println(LazySingleton1.getInstance3());
            },"i="+i).start();
        }
    }
}
class LazySingleton1{
    // 命名全局参数
    //private static LazySingleton1 instance;
    // 为了防止多线程环境中，指令重排导致其他线程获取的对象堆内存并未初始化，导致空指针问题，采取volatile修饰
    private volatile static LazySingleton1 instance;

    // 构造函数私有化
    private LazySingleton1(){}

    // 提供创建实例化的操作函数
    public static LazySingleton1 getInstance(){
        if (instance == null){
            // 为了避免程序执行过快出现实例创建正确，这里增加延迟
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new LazySingleton1();
        }
        return instance;
    }
    // 提供创建实例化的操作函数
    public synchronized static LazySingleton1 getInstance2(){
        if (instance == null){
            // 为了避免程序执行过快出现实例创建正确，这里增加延迟
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new LazySingleton1();
        }
        return instance;
    }

    public  static LazySingleton1 getInstance3(){
        if (instance == null){
            // 锁这个类的字节码文件
            synchronized(LazySingleton1.class){
                // 但此处容易出现：多个线程同时访问的情况
                // 所以此处还需要再做一次安全校验
                if(instance == null){
                    instance = new LazySingleton1();
                    // 1、开辟堆内存空间

                    // 3、引用指向
                    // 2、初始化堆内存
                }
            }
        }
        return instance;
    }
}
